/***************************************************************************
 *   Copyright (C) 2009 by Zheng Yonglei
 *   zhengyonglei@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <QGridLayout>
#include <QTextStream>

#include "Trainer.h"
#include "Logger.h"

Trainer::Trainer(QWidget *parent)
    : QWidget(parent)
{
	ui.setupUi(this);

	QObject::connect(&mTrainerThread, SIGNAL(updateMSE(int, float)), this, SLOT(MSEUpated(int, float)));
	QObject::connect(&mTrainerThread, SIGNAL(statusChanged(const QString&)), this, SLOT(statusChanged(const QString&)));
	QObject::connect(&mTrainerThread, SIGNAL(updateWordSim(QString, vector<int>, vector<float>)), this, SLOT(updateWordSim(QString, vector<int>, vector<float>)));

	QObject::connect(ui.closeButton, SIGNAL(clicked()), this, SLOT(hide()));
	QObject::connect(ui.startTrainingButton, SIGNAL(clicked()), this, SLOT(startTraining()));
	QObject::connect(ui.stopTrainingButton, SIGNAL(clicked()), this, SLOT(stopTraining()));
	QObject::connect(ui.testANNButton, SIGNAL(clicked()), this, SLOT(testANN()));
	QObject::connect(ui.simAvgButton, SIGNAL(clicked()), this, SLOT(simAvg()));

	ui.simSizeSpinBox->setValue(30);
	ui.simSizeSpinBox->setMaximum(9999);
	QObject::connect(ui.wordIDSpinBox, SIGNAL(valueChanged(int)), this, SLOT(testWordIDChanged(int)));
	QObject::connect(ui.simSizeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(simSizeChanged(int)));

	QGridLayout* plotGrid = new QGridLayout(ui.trainingPlotWidget);
	plotGrid->setContentsMargins(0, 0, 0, 0);
	plotGrid->addWidget(&mMSEPlot);

	mMSEPlotCrv.attach(&mMSEPlot);
	mMSEPlot.setAxisAutoScale(QwtPlot::yLeft);
	mMSEPlot.setAxisAutoScale(QwtPlot::xBottom);
	mMSEPlot.setAutoReplot(true);

	QwtPlotGrid* MSEPlotGrid = new QwtPlotGrid;
	MSEPlotGrid->enableXMin(true);
	MSEPlotGrid->enableYMin(true);
	MSEPlotGrid->setMajPen(QPen(Qt::black, 0, Qt::DotLine));
	MSEPlotGrid->setMinPen(QPen(Qt::gray, 0 , Qt::DotLine));
	MSEPlotGrid->attach(&mMSEPlot);

	QGridLayout* wordSimGrid = new QGridLayout(ui.singleWordANNPlot);
	wordSimGrid->setContentsMargins(0, 0, 0, 0);
	wordSimGrid->addWidget(&mWordSimPlot);

	mWordSimPlotCrv.attach(&mWordSimPlot);
	mWordSimPlot.setAxisAutoScale(QwtPlot::xBottom);
	mWordSimPlot.setAxisScale(QwtPlot::yLeft, 0, 1);
	mWordSimPlot.setAxisTitle(QwtPlot::yLeft, tr("Output"));
	mWordSimPlot.setAxisTitle(QwtPlot::xBottom, tr("Interval (day)"));

	QwtPlotGrid* wordSimPlotGrid = new QwtPlotGrid;
	wordSimPlotGrid->enableXMin(true);
	wordSimPlotGrid->enableYMin(true);
	wordSimPlotGrid->setMajPen(QPen(Qt::black, 0, Qt::DotLine));
	wordSimPlotGrid->setMinPen(QPen(Qt::gray, 0 , Qt::DotLine));
	wordSimPlotGrid->attach(&mWordSimPlot);

}

Trainer::~Trainer()
{
	mTrainerThread.exit();
	mTrainerThread.wait();
}

void Trainer::statusChanged(const QString& msg)
{
	ui.trainerStateLabel->setText(msg);
}

void Trainer::startTraining()
{
	mEpochArray.clear();
	mMSEArray.clear();
	mTrainerThread.setTrainData();
	mTrainerThread.start();
}

void Trainer::stopTraining()
{
	mTrainerThread.exit();
}

void Trainer::testANN()
{
	mTrainerThread.testANN();
}

void Trainer::testWordIDChanged(int id)
{
	simSingleWord();
}

void Trainer::simSizeChanged(int size)
{
	simSingleWord();
}

void Trainer::simSingleWord()
{
	int size = ui.simSizeSpinBox->value();
	int id = ui.wordIDSpinBox->value();
	mTrainerThread.testWord(id, size);
}

void Trainer::MSEUpated(int epoch, float mse)
{
	//update plot
	LOG<<"epoch="<<epoch<<"\tmse="<<mse<<endl;
	mEpochArray.push_back(epoch);
	mMSEArray.push_back(mse);

	QwtSymbol sym;

	sym.setStyle(QwtSymbol::Cross);
	sym.setPen(QColor(Qt::black));
	sym.setSize(10);

	mMSEPlotCrv.setSymbol(sym);
	mMSEPlotCrv.setPen(QColor(Qt::darkGreen));
	mMSEPlotCrv.setStyle(QwtPlotCurve::Lines);
	mMSEPlotCrv.setData(mEpochArray, mMSEArray);
}

void Trainer::updateWordSim(QString word, vector<int> intvVect, vector<float> simValVect)
{
	ui.wordInfoLabel->setText(QString("word: %1").arg(word));

	QwtArray<double> intvArray;
	QwtArray<double> simArray;

	for (int i=0; i<intvVect.size(); i++)
		intvArray.push_back(intvVect[i]);

	for (int i=0; i<simValVect.size(); i++)
		simArray.push_back(simValVect[i]);

	QwtSymbol sym;
	sym.setStyle(QwtSymbol::Cross);
	sym.setPen(QColor(Qt::black));
	sym.setSize(10);

	mWordSimPlotCrv.setSymbol(sym);
	mWordSimPlotCrv.setPen(QColor(Qt::darkGreen));
	mWordSimPlotCrv.setStyle(QwtPlotCurve::Lines);
	mWordSimPlotCrv.setData(intvArray, simArray);

	if (word == "avg")
	{
		QwtPlotCurve crv;

		QwtSymbol sym;
		sym.setStyle(QwtSymbol::Cross);
		sym.setPen(QColor(Qt::black));
		sym.setSize(10);

		crv.setSymbol(sym);
		crv.setPen(QColor(Qt::darkGreen));
		crv.setStyle(QwtPlotCurve::Lines);

		crv.attach(&mWordSimPlot);
		crv.setData(intvArray, simArray);
		crv.draw(0, -1);
	}
	else
		mWordSimPlot.replot();
}

void Trainer::simAvg()
{
	mWordSimPlot.replot();
	mTrainerThread.simAvg();
}
